<script lang="ts" setup>
import { message } from '@/utils'
import areaJson from './map_area'
const props = defineProps<{
  show: boolean
  mapPosition?: any[]
  address?: string
}>()
const emit = defineEmits(['update:show', 'confirm', 'setMap'])
const _window = window as any
_window.QQmap = res => {
  _window['jsonp_callback']?.(res)
}
const map = ref({} as any)
const mapKey = ref('B4CBZ-SD3LL-CPAPH-ELXNF-GSRYQ-B6FFD')
const key = ref('')
const addressList = ref<any[]>([])
const markerList = ref<any[]>([])
const markerEventList = ref<any[]>([])
const _index = ref(-1)
const position = ref<any>({})
const store = reactive({
  latlng: props.mapPosition || ([] as any[]), //经纬度
  address: props.address || '', //地址
  zoom: 0, //缩放
  label: {} as any,
  addressInfo: {} as any,
  city: '',
})
/**jsonp请求 */
const jsonp = (url, callback) => {
  const callbackName = 'jsonp_callback'
  const script = document.createElement('script')
  script.src = url + '&callback=' + callbackName
  _window[callbackName] = data => {
    delete window[callbackName]
    document.body.removeChild(script)
    callback(data)
  }
  document.body.appendChild(script)
}
const isNullEmpty = value => [null, 'undefined', [], ''].includes(value)
/**初始化地图*/
const initMap = () => {
  let mapContainer = document.getElementById('mapContainer') as HTMLElement
  //设置Zoom
  map.value = new (_window as any).qq.maps.Map(mapContainer, {
    zoom: store.zoom,
  })
  //创建Label
  map.value.label = new _window.qq.maps.Label({
    map: map.value,
    offset: new _window.qq.maps.Size(15, -12),
    draggable: false,
    clickable: false,
  })
  map.value.setOptions({
    draggableCursor: 'crosshair',
  })
  mapContainer.addEventListener('mouseenter', e => {
    map.value.label.setMap(map.value)
  })
  mapContainer.addEventListener('mouseleave', e => {
    map.value.label.setMap(null)
  })
  _window.qq.maps.event.addListener(map.value, 'mousemove', e => {
    var latlng = e.latLng
    map.value.label.setPosition(latlng)
    map.value.label.setContent(latlng.getLat().toFixed(6) + ',' + latlng.getLng().toFixed(6))
  })
  initcityService()

  //点击获取地址
  _window.qq.maps.event.addListener(map.value, 'click', e => {
    jsonp('https://apis.map.qq.com/ws/geocoder/v1/?location=' + e.latLng.getLat() + ',' + e.latLng.getLng() + '&key=' + mapKey.value + '&output=jsonp&callback=?', res => {
      if (res.status == 0) {
        store.addressInfo = res.result
        store.address = res.result != undefined ? res.result.address : ''
        store.latlng = res.result != undefined ? [res.result.location.lat, res.result.location.lng] : []
        emit('setMap', {
          position: store.latlng,
          address: store.address,
          info: store.addressInfo,
        })
      }
    })
  })
}
nextTick(() => initMap())
const initcityService = () => {
  let cityService = new _window.qq.maps.CityService({
    complete: result => {
      map.value.setCenter(result.detail.latLng)
      store.city = result.detail.name
      store.latlng = [result.detail.latLng.lat, result.detail.latLng.lng]
      locationService()
    },
  })
  cityService.searchLocalCity()
}
const locationService = (done?, title?) => {
  const location = store.latlng.join(',')
  jsonp('https://apis.map.qq.com/ws/geocoder/v1/?location=' + location + '&key=' + mapKey.value + '&output=jsonp&callback=?', res => {
    if (res.status == 0 && res.result) {
      store.addressInfo = res.result
      title ? ((store.addressInfo.address_component.street_number = title), (store.addressInfo.address = store.addressInfo.address_component.province + store.addressInfo.address_component.city + store.addressInfo.address_component.district + store.addressInfo.address_component.street + title)) : ''
      let center = new _window.qq.maps.LatLng(...store.latlng)
      map.value.panTo(center)
      let marker = new _window.qq.maps.Marker({
        position: center,
        map: map.value,
      })
      store.address = res.result.address
      store.city = res.result.address_component.city
      if (done == 'close') {
        emit('setMap', {
          position: store.latlng,
          address: store.address,
          info: store.addressInfo,
        })
      }
    }
  })
}
const handleSearch = () => {
  if (!isNullEmpty(key.value)) {
    jsonp('https://apis.map.qq.com/ws/place/v1/search?keyword=' + key.value + '&boundary=region(' + store.city + ',0)&page_size=9&page_index=1&key=' + mapKey.value + '&output=jsonp&&callback=?', res => {
      if (res.status == 0) {
        res.data.map((item, index) => {
          item.id = 'mapItem' + index
          item.active = false
          item.hover = false
          return item
        })
        addressList.value = res.data
        setMarker(res)
        map.value.setZoom(14)
      }
    })
  } else {
    addressList.value = []
    jsonp('https://apis.map.qq.com/ws/geocoder/v1/?region=' + store.city + '&address=' + store.city + '&key=' + mapKey.value + '&output=jsonp&&callback=?', res => {
      if (res.status == 0) {
        map.value.setCenter(new _window.qq.maps.LatLng(res.result.location.lat, res.result.location.lng))
        map.value.setZoom(14)
      }
    })
  }
}
/**设置Marker */
const setMarker = res => {
  let latlngBounds = new _window.qq.maps.LatLngBounds()
  //删除Marker
  markerList.value.forEach((item: any) => {
    item.setMap(null)
  })
  //删除Marker事件
  markerEventList.value.forEach(item => {
    _window.qq.maps.event.removeListener(item)
  })

  markerEventList.value = []
  markerList.value = []
  res.data.forEach((item, index) => {
    let latlng = new _window.qq.maps.LatLng(item.location.lat, item.location.lng)
    latlngBounds.extend(latlng)
    //创建Marker
    let marker = new _window.qq.maps.Marker({
      map: map.value,
      position: latlng,
      zIndex: 10,
    })
    marker.index = index
    marker.isClicked = false
    setAnchor(marker, false)
    markerList.value.push(marker)
    //点击事件
    markerEventList.value.push(
      _window.qq.maps.event.addDomListener(marker, 'click', function () {
        setFlagClicked(_index.value)
      })
    )
    markerEventList.value.push(
      _window.qq.maps.event.addDomListener(marker, 'mouseover', function () {
        setCurrentMarker(_index.value, true)
        hoverAddress(_index.value, true)
        store.label.setContent(position.value.getLat().toFixed(6) + ',' + position.value.getLng().toFixed(6))
        store.label.setPosition(position.value)
        store.label
          .setOptions({
            offset: new _window.qq.maps.Size(15, -20),
          })(document.getElementById('mapItem' + _index.value) as HTMLElement)
          .scrollIntoView({ behavior: 'smooth' })
      })
    )
    markerEventList.value.push(
      _window.qq.maps.event.addDomListener(marker, 'mouseout', function () {
        setCurrentMarker(_index.value, false)
        hoverAddress(_index.value, false)
        store.label.setOptions({
          offset: new _window.qq.maps.Size(15, -12),
        })
      })
    )
    map.value.fitBounds(latlngBounds)
  })
  if (markerList.value.length > 0) {
    map.value.setCenter(markerList.value[0].position)
  }
}
const setAnchor = (marker, flag) => {
  let left = marker.index * 27
  let anchor = new _window.qq.maps.Point(10, 30),
    origin = new _window.qq.maps.Point(left, flag ? 35 : 0),
    size = new _window.qq.maps.Size(27, 33),
    icon = new _window.qq.maps.MarkerImage('/images/marker10.png', size, origin, anchor)
  marker.setIcon(icon)
}
/**选择地址*/
const selectAddress = index => {
  setCurrentAddress(index)
  setFlagClicked(index)
  map.value.setCenter(markerList.value[index].position)
}
const setCurrentAddress = mapIndex => {
  addressList.value.map((item: any, index) => {
    item.active = index == mapIndex
    return item
  })
}
const setCurrentMarker = (index, flag) => {
  if (flag || (!flag && !markerList.value[index].isClicked)) {
    setAnchor(markerList.value[index], flag)
  }
}
const hoverAddress = (mapIndex, flag) => {
  addressList.value.map((item: any, index) => {
    item.hover = flag ? index == mapIndex : flag
    return item
  })
}
const setFlagClicked = mapIndex => {
  markerList.value.map((item, index) => {
    if (index == mapIndex) {
      item.isClicked = true
      item.setZIndex(10)
      setAnchor(item, true)
      store.latlng = [item.getPosition().getLat().toFixed(6), item.getPosition().getLng().toFixed(6)]
      store.address = addressList.value[mapIndex].address
      store.addressInfo = addressList.value[mapIndex]
      locationService('close', addressList.value[mapIndex].title)
    } else {
      item.isClicked = false
      item.setZIndex(9)
      setAnchor(item, false)
    }
    return item
  })
  setCurrentAddress(mapIndex)
  ;(document.getElementById('mapItem' + mapIndex) as HTMLElement).scrollIntoView({ behavior: 'smooth' })
}
const handleSubmit = () => {
  if (store.latlng == null) {
    message({ type: 'error', content: '请定位坐标' })
  } else {
    emit('setMap', {
      position: store.latlng,
      address: store.address,
      info: store.addressInfo,
    })
  }
}
</script>
<template>
  <CModal v-model:visible="props.show" width="800px" @cancel="emit('update:show', false)" title="坐标拾取">
    <div class="map_search">
      <a-row :gutter="20" style="margin-bottom: 20px">
        <a-col :span="4">
          <a-select v-model="store.city" @change="handleSearch" placeholder="请选择" allow-search>
            <a-optgroup :label="area.name" v-for="area in areaJson.areas">
              <a-option v-for="item in area.citys" :value="item.name">{{ item.name }}</a-option>
            </a-optgroup>
          </a-select>
        </a-col>
        <a-col :span="6">
          <a-input v-model="key" placeholder="请输入地址" @input="handleSearch" />
        </a-col>
        <a-space style="margin-left: auto">
          <a-input-number style="width: 100px" readonly v-model="store.latlng[0]" />
          <a-input-number style="width: 100px" readonly v-model="store.latlng[1]" />
          <a-button type="primary" @click="handleSubmit">确定</a-button>
        </a-space>
      </a-row>
      <div class="map_box">
        <div class="map_panel">
          <div class="panel_left">
            <b>{{ store.city }}</b
            >，缩放等级：{{ store.zoom }}
          </div>
          <div class="panel_right">{{ store.address }}</div>
        </div>
        <div class="map_main">
          <div class="map_left">
            <div v-if="key">
              <div class="map_list" v-if="addressList.length > 0">
                <div class="map_item" :id="item.id" :class="{ active: item.active || item.hover }" v-for="(item, index) in addressList" @click="selectAddress(index)" @mouseover="setCurrentMarker(index, true)" @mouseout="setCurrentMarker(index, false)" :key="index">
                  <div class="item_icon">
                    <div class="icon">{{ index + 1 }}</div>
                  </div>
                  <div class="item_box">
                    <div class="title">{{ item.title }}</div>
                    <div class="row">
                      <div class="name">地址：</div>
                      <div class="val">{{ item.address }}</div>
                    </div>
                    <div class="row" v-if="item.tel">
                      <div class="name">电话：</div>
                      <div class="val">{{ item.tel }}</div>
                    </div>
                    <div class="row">
                      <div class="name">坐标：</div>
                      <div class="val">{{ item.location.lat.toFixed(6) }},{{ item.location.lng.toFixed(6) }}</div>
                    </div>
                  </div>
                </div>
              </div>
              <div class="map_empty" v-else>对不起，没有搜索到你要找的结果</div>
            </div>
            <div class="map_msg" v-else>
              <div class="msg_title">功能简介：</div>
              <p>1、支持地址 精确/模糊 查询；</p>
              <p>2、支持POI点坐标显示；</p>
              <p>3、坐标鼠标跟随显示；</p>
              <div class="msg_title">使用说明：</div>
              <p>在搜索框搜索关键词后，地图上会显示相应poi点，同时左侧显示对应该点的信息，点击某点或某信息，右上角会显示相应该点的坐标和地址。</p>
            </div>
          </div>
          <div class="map_container" id="mapContainer"></div>
        </div>
      </div>
    </div>
  </CModal>
</template>
<style lang="less" scoped>
.map_box {
  width: 100%;
  border: 1px solid #dcdfe6;
}
.map_search {
  padding-bottom: 20px;
}
.map_search .el-col-24 {
  width: auto;
  padding-right: 10px;
}
.map_box .map_panel {
  background: #f9f9f9;
  line-height: 40px;
  height: 40px;
  overflow: hidden;
  border-bottom: 1px solid #dcdfe6;
  font-size: 12px;
  padding: 0 10px;
  display: flex;
  display: -webkit-flex;
  display: -webkit-box;
}
.map_box .map_panel .panel_left b {
  font-size: 14px;
  font-weight: bold;
  color: #000;
}
.map_box .map_panel .panel_right {
  text-align: right;
  flex: 1;
  -webkit-flex: 1;
  -webkit-box-flex: 1;
  font-weight: bold;
}
.map_box .map_container {
  height: 450px;
  flex: 1;
  -webkit-flex: 1;
  -webkit-box-flex: 1;
}
.map_box .map_main {
  display: flex;
  display: -webkit-flex;
  display: -webkit-box;
}
.map_box .map_main .map_left {
  width: 260px;
  height: 450px;
  overflow: auto;
  overflow-x: hidden;
  border-right: 1px solid #dcdfe6;
}
.map_box .map_main .map_empty {
  text-align: center;
  font-size: 12px;
  padding: 20px;
}
.map_box .map_main .map_list .map_item {
  display: flex;
  display: -webkit-flex;
  display: -webkit-box;
  padding: 10px;
  cursor: pointer;
}
.map_box .map_main .map_list .map_item:hover,
.map_box .map_main .map_list .map_item.active {
  background: rgb(243, 243, 243);
}
.map_box .map_main .map_list .map_item .icon {
  width: 17px;
  height: 17px;
  border-radius: 50%;
  color: #00ce9b;
  border: 1px solid #99ebd7;
  background: #e6faf5;
  line-height: 17px;
  font-weight: bold;
  text-align: center;
}
.map_box .map_main .map_list .map_item .item_box {
  padding-left: 10px;
  font-size: 12px;
  flex: 1;
  -webkit-flex: 1;
  -webkit-box-flex: 1;
}
.map_box .map_main .map_list .map_item .item_box .title {
  font-size: 14px;
  font-weight: bold;
  padding-bottom: 5px;
}
.map_box .map_main .map_list .map_item .item_box .row {
  display: flex;
  display: -webkit-flex;
  display: -webkit-box;
  padding-bottom: 5px;
}
.map_box .map_main .map_list .map_item .item_box .row .val {
  flex: 1;
  -webkit-flex: 1;
  -webkit-box-flex: 1;
}
.map_box .map_main .map_left .map_msg {
  padding: 10px;
  font-size: 12px;
}
.map_box .map_main .map_left .map_msg .msg_title {
  color: #000;
  font-weight: bold;
  font-size: 14px;
}
</style>
